#ifndef MODBUS_COMMUNICATION_H
#define MODBUS_COMMUNICATION_H
#include <errno.h>
#include <vector>
#include <string>
#include <queue>
#include <mutex>
#include <thread>
#include "modbus.h"
#include "rclcpp/rclcpp.hpp"
#include "common.h"

#define DEBUG 0
#define DEVICETREE_RS485 "RS485_"
#define DEVICETREE_XNET  "XNET"

enum {
    TCP,
    TCP_PI,
    RTU
};
enum MB_ERRO {
    NORMALL = 0,
    ALREADY_INIT_ERRO = -1,
    IS_SLAVE_ERRO = -2,
    MALLOC_BIT_NULL = -3,
    MALLOC_REG_NULL = -4,
    CTX_NULLPTR =  -5,
    FAILED_CONNECT =  1,
    listen_TCP_FAILED= -6,
    NO_INIT= -7
};

class ModbusCommunication
{
        /*!
    * \brief The uart port parameter. 
    * Used for read modbus slave data .
    */
    struct UartParamater {
        std::string port;
        int baudrate;
        int data_bits;        
        std::string patity;
        int stop_bit; 
    };
    typedef struct UartParamater uartPara;
public:
    static modbus_mapping_t *mb_mapping;    
public:
    ModbusCommunication(const std::shared_ptr<rclcpp::Node> node);
    virtual ~ModbusCommunication();
    virtual void start() =0;
    virtual void stop() =0;    
    virtual int init(std::string prefix) =0;
    virtual int init(std::string host_ip,int host_port,int slave_id) =0;
    void get_linkpara(std::string prefix);
    int modbusServer_set_Word16register( int reg_addr, const uint16_t value, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_input_registers);
    int set_bit_from_index( int reg_addr, int idx, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_input_registers);
    int modbusServer_set_Int32register( int reg_addr, const uint32_t value, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_input_registers);
    int modbusServer_set_Long64register( int reg_addr, const uint64_t value, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_input_registers);
    uint16_t modbusServer_get_register( int reg_addr, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_registers);
    int modbusServer_set_bit( int bit_addr, const uint8_t value, uint8_t *pArr= ModbusCommunication::mb_mapping->tab_input_bits);
    int modbusServer_set_bits( int bit_addr, unsigned int nb_bits,const uint8_t *pValue, uint8_t *pArr= ModbusCommunication::mb_mapping->tab_input_bits);
    bool modbusServer_get_bit( int reg_addr, uint8_t *pArr= ModbusCommunication::mb_mapping->tab_bits);
    int modbusServer_set_float( int reg_addr, const float f, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_input_registers);
    float modbusServer_get_float( int reg_addr, uint16_t *pArr= ModbusCommunication::mb_mapping->tab_registers);
    bool write_output_io_bits(const int& start_addr, const int& count_io_bits, const uint8_t *need_set_levels);
    bool write_single_io_bit(const int& addr, const bool& level) ;
    bool read_input_io_bits(const int& start_addr, const int& count_io_bits, uint8_t *ret_dest_status);
    modbus_mapping_t * getMb_mapping(){ return mb_mapping;};
protected:
    std::shared_ptr<rclcpp::Node> nh_;
    std::mutex m_mutex;
    std::timed_mutex m_quit_mutex;
    bool m_init_ok;
    std::thread m_thread;
    modbus_t   *m_ctx;
 
    std::string m_host_ip;
    int  m_host_port;

    int m_use_backend;
    uint32_t m_resptime;
    uartPara  m_uart;
    bool    m_debug,
            m_is_slave,
            m_reconnect;
};

#endif